﻿using System;
using CoreRay;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CoreRay.Testing
{
    //-----------------------------------------------------------------------------------------
    /// <summary>
    /// Test class for <see cref="Vector3"/> struct.
    /// </summary>
    //-----------------------------------------------------------------------------------------
    [TestClass]
    public class Vector3Test
    {
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for <see cref="Vector3"/> Constructor.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void Vector3ConstructorTest()
        {
            float x = -56.2f;
            float y = 0.006f;
            float z = 153.254f;

            Vector3 target = new Vector3(x, y, z);

            Assert.IsTrue(target.X == x && target.Y == y && target.Z == z);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Magnitude.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void MagnitudeTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);

            Assert.AreEqual<float>((float) System.Math.Sqrt(target.X * target.X + target.Y * target.Y + target.Z * target.Z), target.Magnitude);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for MagnitudeSquared.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void MagnitudeSquaredTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);

            Assert.AreEqual(target.X * target.X + target.Y * target.Y + target.Z * target.Z, target.MagnitudeSquared);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Normalize.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void NormalizeTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 expected = new Vector3(target.X / target.Magnitude, target.Y / target.Magnitude, target.Z / target.Magnitude);

            Assert.AreEqual(expected, target.Normalize());
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Normalize with a zero input vector.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void NormalizeZeroVectorTest()
        {
            Vector3 target = Vector3.ZeroVector;

            Assert.AreEqual(Vector3.ZeroVector, target.Normalize());
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for IsNormalized.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void IsNormalizedVectorTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f).Normalize();

            bool actual = vector.IsNormalized;
            bool expected = true;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for IsNormalized with a not normalized vector.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void IsNormalizedFalseVectorTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);

            bool actual = vector.IsNormalized;
            bool expected = false;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for CrossProduct.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void CrossProductTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            Vector3 actual = Vector3.CrossProduct(vector1, vector2);
            Vector3 expected = new Vector3(vector1.Y * vector2.Z - vector1.Z * vector2.Y, vector1.Z * vector2.X - vector1.X * vector2.Z, vector1.X * vector2.Y - vector1.Y * vector2.X);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Distance.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void DistanceTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            float actual = Vector3.Distance(vector1, vector2);
            float expected = (vector1 - vector2).Magnitude;
            
            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        ///A test for DistanceSquared.
        ///</summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void DistanceSquaredTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            float actual = Vector3.DistanceSquared(vector1, vector2);
            float expected = (vector1 - vector2).MagnitudeSquared;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for ComputeAngle.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void ComputeAngleTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            float actual = Vector3.ComputeAngle(vector1, vector2);
            float expected = (float) System.Math.Acos((vector1 * vector2) / (vector1.Magnitude * vector2.Magnitude));
            
            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for ComputeAngle with a zero vector.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ComputeAngleZeroVectorTest()
        {
            Vector3 vector1 = Vector3.ZeroVector;
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            Vector3.ComputeAngle(vector1, vector2);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Negate.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void NegateTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);
            
            Vector3 actual = Vector3.Negate(vector);
            Vector3 expected = new Vector3(-vector.X, -vector.Y, -vector.Z);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for unary negation operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_UnaryNegationTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);

            Vector3 actual = -vector;
            Vector3 expected = new Vector3(-vector.X, -vector.Y, -vector.Z);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Add.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void AddTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            Vector3 actual = Vector3.Add(vector1, vector2);
            Vector3 expected = new Vector3(vector1.X + vector2.X, vector1.Y + vector2.Y, vector1.Z + vector2.Z);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for addition operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_AdditionTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            Vector3 actual = vector1 + vector2;
            Vector3 expected = new Vector3(vector1.X + vector2.X, vector1.Y + vector2.Y, vector1.Z + vector2.Z);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Subtract.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void SubtractTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            Vector3 actual = Vector3.Subtract(vector1, vector2);
            Vector3 expected = new Vector3(vector1.X - vector2.X, vector1.Y - vector2.Y, vector1.Z - vector2.Z);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for subtraction operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_SubtractionTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            Vector3 actual = vector1 - vector2;
            Vector3 expected = new Vector3(vector1.X - vector2.X, vector1.Y - vector2.Y, vector1.Z - vector2.Z);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        ///A test for Multiply.
        ///</summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void MultiplyTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);
            float scalar = 3.5f;
            
            Vector3 actual = Vector3.Multiply(vector, scalar);
            Vector3 expected = new Vector3(vector.X * scalar, vector.Y * scalar, vector.Z * scalar);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        ///A test for multiply scalar operator.
        ///</summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_MultiplyScalarTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);
            float scalar = 3.5f;

            Vector3 actual = vector * scalar;
            Vector3 expected = new Vector3(vector.X * scalar, vector.Y * scalar, vector.Z * scalar);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Divide.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void DivideTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);
            float scalar = 3.5f;
            
            Vector3 actual = Vector3.Divide(vector, scalar);
            Vector3 expected = new Vector3(vector.X / scalar, vector.Y / scalar, vector.Z / scalar);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for divide by zero.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        [ExpectedException(typeof(DivideByZeroException))]
        public void DivideZeroTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);
            float scalar = 0.0f;

            Vector3 actual = Vector3.Divide(vector, scalar);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for division operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_DivisionTest()
        {
            Vector3 vector = new Vector3(-56.2f, 0.006f, 153.254f);
            float scalar = 6.5f;

            Vector3 actual = (vector / scalar);
            Vector3 expected = new Vector3(vector.X / scalar, vector.Y / scalar, vector.Z / scalar);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for DotProduct.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void DotProductTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            float actual = Vector3.DotProduct(vector1, vector2);
            float expected = vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for dot product operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_DotProductTest()
        {
            Vector3 vector1 = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 vector2 = new Vector3(83.5f, 856.2f, -56.1457f);

            float actual = vector1 * vector2;
            float expected = vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Equals.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void EqualsTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 other = new Vector3(-56.2f, 0.006f, 153.254f);

            bool expected = true;
            bool actual = target.Equals(other);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for inequality.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void UnequalsTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 other = new Vector3(83.5f, 856.2f, -56.1457f);

            bool expected = false;
            bool actual = target.Equals(other);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for equality operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_EqualityTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 other = new Vector3(-56.2f, 0.006f, 153.254f);

            bool expected = true;
            bool actual = target.Equals(other);

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        ///A test for op_Inequality
        ///</summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_InequalityTest()
        {
            Vector3 target = new Vector3(-56.2f, 0.006f, 153.254f);
            Vector3 other = new Vector3(83.5f, 856.2f, -56.1457f);

            bool expected = false;
            bool actual = target.Equals(other);

            Assert.AreEqual(expected, actual);
        }      
    }
}
